<?php

namespace Xin\LaravelFortify\Foundation\Http;

use Illuminate\Http\Request;
use Illuminate\Support\Env;
use Illuminate\Support\Facades\Request as RequestFacade;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Str;

class ModuleContext
{
	/**
	 * @var array[]
	 */
	protected static $allowList = [
		'api' => [
			'prefix' => 'api',
			'namespace' => 'App\Http\Controllers',
		],
		'admin' => [
			'prefix' => 'adminapi',
			'namespace' => 'App\Admin\Controllers',
		],
		'web' => [
			'prefix' => '',
			'namespace' => 'App\Http\Controllers',
		],
	];

	/**
	 * @var string
	 */
	protected static $default = 'web';

	/**
	 * 获取默认模块
	 * @return string
	 */
	public static function getDefault(): string
	{
		return self::$default;
	}

	/**
	 * 设置默认模块
	 * @param string $default
	 * @return void
	 */
	public static function setDefault(string $default): void
	{
		self::$default = $default;
	}

	/**
	 * 获取允许的模块
	 * @return array[]
	 */
	public static function getAllowList(): array
	{
		return self::$allowList;
	}

	/**
	 * 设置允许的模块
	 * @param array $allowList
	 * @return void
	 */
	public static function setAllowList(array $allowList): void
	{
		self::$allowList = $allowList;
	}

	/**
	 * 获取模块配置
	 * @param string $module
	 * @return array
	 */
	public static function get($module)
	{
		return self::$allowList[$module];
	}

	/**
	 * 设置模块配置
	 * @param string $module
	 * @param array $config
	 * @return void
	 */
	public static function set($module, $config, $merge = true)
	{
		if ($merge) {
			self::$allowList[$module] = array_replace_recursive(self::$allowList[$module], $config);
		} else {
			self::$allowList[$module] = $config;
		}
	}

	/**
	 * 根据URL路径查找模块
	 * @param string $urlFirstPath
	 * @return string|null
	 */
	public static function findForUrlFirstPath($urlFirstPath)
	{
		foreach (self::getAllowList() as $key => $value) {
			if ($value['prefix'] == $urlFirstPath) {
				return $key;
			}
		}

		return null;
	}

	/**
	 * 解析模块
	 * @param string $requestPath
	 * @return array
	 */
	public static function parse(string $requestPath): array
	{
		$module = self::getDefault();
		$modulePath = $requestPath;

		if ($index = strpos($requestPath, '/')) {
			$urlFirstPath = substr($requestPath, 0, $index);
			if ($module = self::findForUrlFirstPath($urlFirstPath)) {
				$modulePath = substr($requestPath, $index + 1);
			} else {
				$module = self::$default;
			}
		} else {
			if (in_array($requestPath, self::getAllowList())) {
				$module = $requestPath;
				$modulePath = '';
			}
		}

		return [$module, $modulePath];
	}

	/**
	 * 初始化请求模块
	 * @param Request $request
	 * @return array
	 */
	public static function init(Request $request)
	{
		if ($request->attributes->has('module')) {
			return [$request->attributes->get('module'), $request->attributes->get('modulePath')];
		}

		[$module, $modulePath] = self::parse($request->path());
		$request->attributes->add([
			'module' => $module,
			'modulePath' => $modulePath,
		]);

		return [$module, $modulePath];
	}

	/**
	 * 注册请求器相关宏操作
	 * @return void
	 */
	public static function registerMacros()
	{
		Request::macro('module', function () {
			/** @var Request $this */
			return ModuleContext::init($this)[0];
		});

		Request::macro('modulePath', function () {
			/** @var Request $this */
			return ModuleContext::init($this)[1];
		});
	}

	/**
	 * 定义 Router
	 * @param string $module
	 * @param string $routePath
	 * @param string|null $subPrefix
	 * @return \Illuminate\Routing\RouteRegistrar
	 */
	public static function defineRoute($module, $routePath, $subPrefix = null)
	{
		if (!file_exists($routePath)) {
			return null;
		}

		// 模块配置
		$moduleConfig = self::get($module);

		// 定义路由
		$router = Route::middleware($module);

		// 路由前缀
		// $prefix = $module === self::getDefault() ? '' : Str::snake($module);
		$prefix = $moduleConfig['prefix'];
		$fullPrefix = $prefix . ($prefix && $subPrefix ? '/' : '') . $subPrefix;
		$router->prefix($fullPrefix);

		// 路由名称前缀
		$name = $module . '.' . $subPrefix . ($subPrefix ? '.' : '');
		$router->name($name);

		// 命名空间
		if (!empty($moduleConfig['namespace'])) {
			$router->namespace($moduleConfig['namespace']);
		}

		return $router->group($routePath);
	}

	/**
	 * 是否注册全部路由
	 * @return bool
	 */
	public static function isRegisterAllRoutes()
	{
		static $isRegisterAllRoutes = null;

		if ($isRegisterAllRoutes === null) {
			$isRegisterAllRoutes = app()->runningInConsole() ||
				Str::contains(RequestFacade::server('SCRIPT_NAME'), "frankenphp-worker") ||
				Str::contains(RequestFacade::server('SCRIPT_NAME'), "roadrunner-worker") ||
				Env::get('REGISTER_ALL_ROUTES', false);
		}

		return $isRegisterAllRoutes;
	}

	/**
	 * 是否允许注册路由
	 * @param string $module
	 * @return bool
	 */
	public static function isAllowRegisterRoutes($module)
	{
		return RequestFacade::module() === $module || self::isRegisterAllRoutes();
	}
}
